﻿using System;
using System.Collections.Generic;
using System.Linq;
using ORM.Business.Interfaces;
//using ORM.Business.LevelManagement;
using ORM.Business.Models;
using ORM.Business.Models.Caching;
using ORM.Common;
using ORM.Resources;
using ORM.Business.Feedbacks;
using ORM.Business.Models.Entities;
using ORM.Common.Logging;

namespace ORM.Business.Repositories
{
    public class UserRepository : IUserRepository
    {
        public Feedback<IList<user>> GetSimilarUsers(string username)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    if (username == null)
                    {
                        var queryable = entities.Users
                            .Where(u => !u.IsDeleted)
                            .Select(u => new
                            {
                                u.Id,
                                u.Username,
                                u.Email,
                                u.AvatarUrl,
                                u.Ponit,
                                u.Level,
                                u.LastLogin,
                                u.CreatedDate
                            })
                            .OrderByDescending(i => i.Ponit);

                        IList<user> users = new List<user>();
                        foreach (var q in queryable)
                        {
                            users.Add(new user
                            {
                                Id = q.Id,
                                Username = q.Username,
                                Email = q.Email,
                                AvatarUrl = q.AvatarUrl,
                                Ponit = q.Ponit,
                                Level = q.Level,
                                LastLogin = q.LastLogin,
                                CreatedDate = q.CreatedDate
                            });
                        }

                        return new Feedback<IList<user>>(true, null, users);
                    }
                    else
                    {

                        var queryable = entities.Users
                           .Where(u => !u.IsDeleted && u.Username.Contains(username))
                           .Select(u => new
                           {
                               u.Id,
                               u.Username,
                               u.Email,
                               u.AvatarUrl,
                               u.Ponit,
                               u.Level,
                               u.LastLogin,
                               u.CreatedDate
                           })
                           .OrderByDescending(i => i.Ponit);

                        IList<user> users = new List<user>();
                        foreach (var q in queryable)
                        {
                            users.Add(new user
                            {
                                Id = q.Id,
                                Username = q.Username,
                                Email = q.Email,
                                AvatarUrl = q.AvatarUrl,
                                Ponit = q.Ponit,
                                Level = q.Level,
                                LastLogin = q.LastLogin,
                                CreatedDate = q.CreatedDate
                            });
                        }

                        return new Feedback<IList<user>>(true, null, users);
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<IList<user>>(false, Messages.GeneralError);
            }
        }


        public Feedback<user> DeleteUser(int id)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    user user = entities.Users.Single(i => i.Id == id && !i.IsDeleted);

                    // Cannot delete admin
                    if (user.Email.Equals(AppConfigs.AdminEmail))
                    {
                        return new Feedback<user>(false, Messages.CannotDeleteAdminInfo);
                    }

                    user.IsDeleted = true;
                    user.LastUpdate = DateTime.Now;

                    //Remove user roles
                    foreach (var a in entities.UserRoles.Where(t => t.RoleId == id).ToList())
                        entities.UserRoles.Remove(a);
                    foreach (var guide in entities.Guides.Where(i => i.PostedBy == id).ToList())
                    {
                        guide.IsDeleted = true;
                    }
                    foreach (var question in entities.Questions.Where(i => i.PostedById == id).ToList())
                    {
                        question.IsDeleted = true;
                    }
                    foreach (var answer in entities.Answers.Where(i => i.PostedById == id).ToList())
                    {
                        answer.IsDeleted = true;
                    }
                    foreach (var comment in entities.GuideComments.Where(i => i.PostedBy == id).ToList())
                    {
                        comment.IsDeleted = true;
                    }
                    entities.SaveChanges();

                    return new Feedback<user>(true, null, user);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<user>(false, Messages.GeneralError);
            }
        }

        public Feedback<user> ViewOtherUserInformaton(int id)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    var record = entities.Users
                        .Where(i => i.Id == id && !i.IsDeleted)
                        .Select(i => new
                        {
                            i.Username,
                            i.Sex,
                            i.Birthday,
                            i.Hobbies,
                            i.SocialNetworkUrl,
                            i.LocationId,
                            i.AvatarUrl,
                            i.CreatedDate,
                            i.Ponit,
                            i.Level
                        })
                        .SingleOrDefault();

                    if (record == null)
                        return new Feedback<user>(false, Messages.GetUser_NotFound);

                    user user = new user
                    {
                        Id = id,
                        Username = record.Username,
                        Sex = record.Sex,
                        Birthday = record.Birthday,
                        Hobbies = record.Hobbies,
                        SocialNetworkUrl = record.SocialNetworkUrl,
                        LocationId = record.LocationId,
                        AvatarUrl = record.AvatarUrl,
                        CreatedDate = record.CreatedDate,
                        Ponit = record.Ponit,
                        Level = record.Level
                    };
                    user.NumberOfGuides = entities.Guides.Count(i => i.PostedBy == id && !i.IsDeleted);
                    user.NumberOfQuestions = entities.Questions.Count(i => i.PostedById == id && !i.IsDeleted);

                    user.NumberOfAnswers = entities.Answers.Count(i => i.PostedById == id && !i.IsDeleted);
                    return new Feedback<user>(true, null, user);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<user>(false);
            }
        }

        public Feedback<IList<user>> GetAllUsers() //hungnm dang sua
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    var queryable = entities.Users
                        .Where(u => !u.IsDeleted)
                        .Select(u => new
                        {
                            u.Id,
                            u.Username,
                            u.Email,
                            u.AvatarUrl,
                            u.Ponit,
                            u.CreatedDate
                        })
                        .OrderByDescending(i => i.CreatedDate);

                    IList<user> users = new List<user>();
                    foreach (var q in queryable)
                    {
                        users.Add(new user
                        {
                            Id = q.Id,
                            Username = q.Username,
                            Email = q.Email,
                            AvatarUrl = q.AvatarUrl,
                            Ponit = q.Ponit
                        });
                    }

                    return new Feedback<IList<user>>(true, null, users);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<IList<user>>(false, Messages.GeneralError);
            }
        }
        public Feedback<IList<user>> GetTopUsers() 
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    var queryable = entities.Users
                        .Where(u => !u.IsDeleted)
                        .Select(u => new
                        {
                            u.Id,
                            u.Username,
                            u.AvatarUrl,
                            u.Ponit,
                        })
                        .OrderByDescending(i => i.Ponit).Take(10);

                    IList<user> users = new List<user>();
                    foreach (var q in queryable)
                    {
                        users.Add(new user
                        {
                            Id = q.Id,
                            Username = q.Username,
                            AvatarUrl = q.AvatarUrl,
                            Ponit = q.Ponit
                        });
                    }

                    return new Feedback<IList<user>>(true, null, users);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<IList<user>>(false, Messages.GeneralError);
            }
        }

  
        public Feedback<user> GetPersonalInfo(int id)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    var record = entities.Users
                        .Where(i => i.Id == id && !i.IsDeleted)
                        .Select(i => new
                        {
                            i.Username,
                            i.Password,
                            i.Email,
                            i.AvatarUrl,
                            i.Level,
                            i.Sex,
                            i.Birthday,
                            i.Hobbies,
                            i.LocationId,
                            i.SocialNetworkUrl,
                            i.CreatedDate,
                            i.Ponit,
                            i.TodayPoint
                        })
                        .SingleOrDefault();

                    user user;
                    if (record.LocationId != null)
                    {
                        var locationRecord = entities.Locations.Where(i => i.Id == record.LocationId).Select(i => new { i.Name }).SingleOrDefault();

                        user = new user
                        {
                            Id = id,
                            Username = record.Username,
                            Email = record.Email,
                            Password = record.Password,
                            AvatarUrl = record.AvatarUrl,
                            Level = record.Level,
                            Sex = record.Sex,
                            Birthday = record.Birthday,
                            Hobbies = record.Hobbies,
                            LocationId = record.LocationId,
                            SocialNetworkUrl = record.SocialNetworkUrl,
                            CreatedDate = record.CreatedDate,
                            Ponit = record.Ponit,
                            TodayPoint = record.TodayPoint,
                            Location = new Location { Id = record.LocationId.Value, Name = locationRecord.Name }
                        };
                    }
                    else
                    {
                        user = new user
                        {
                            Id = id,
                            Username = record.Username,
                            Email = record.Email,
                            Password = record.Password,
                            AvatarUrl = record.AvatarUrl,
                            Level = record.Level,
                            Sex = record.Sex,
                            Birthday = record.Birthday,
                            Hobbies = record.Hobbies,
                            LocationId = record.LocationId,
                            SocialNetworkUrl = record.SocialNetworkUrl,
                            CreatedDate = record.CreatedDate,
                            Ponit = record.Ponit,
                            TodayPoint = record.TodayPoint
                        };
                    }

                    user.NumberOfGuides = entities.Guides.Count(i => i.PostedBy == id && !i.IsDeleted);
                    user.NumberOfQuestions = entities.Questions.Count(i => i.PostedById == id && !i.IsDeleted);

                    user.NumberOfAnswers = entities.Answers.Count(i => i.PostedById == id && !i.IsDeleted);

                    return new Feedback<user>(true, null, user);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<user>(false, Messages.GeneralError);
            }
        }

        public Feedback<string> UpdateUserProfile(user currentUser)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    user user = entities.Users.Single(i => i.Id == currentUser.Id);
                    string oldAvatar = null;

                    user.Sex = currentUser.Sex;
                    user.Birthday = currentUser.Birthday;
                    user.Hobbies = currentUser.Hobbies;
                    user.SocialNetworkUrl = currentUser.SocialNetworkUrl;
                    user.LocationId = currentUser.LocationId;
                    if (currentUser.AvatarUrl != null)
                    {
                        oldAvatar = user.AvatarUrl;
                        user.AvatarUrl = currentUser.AvatarUrl;
                    }
                    user.LastUpdate = DateTime.Now;

                    entities.SaveChanges();

                    return new Feedback<string>(true, null, oldAvatar);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<string>(false, Messages.GeneralError);
            }
        }

        public Feedback<string> RemoveAvatar(int id)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    user user = entities.Users.Single(i => i.Id == id);
                    string oldAvatar = user.AvatarUrl;
                    user.AvatarUrl = "~/Content/images/users/avatars/default-avatar-200x200_small.jpg";
                    user.LastUpdate = DateTime.Now;

                    entities.SaveChanges();

                    return new Feedback<string>(true, null, oldAvatar);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<string>(false, Messages.GeneralError);
            }
        }

        public Feedback<user> GetUserDetails(int id)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    user user = entities.Users.Include("UserRoles").SingleOrDefault(i => i.Id == id && !i.IsDeleted);
                    if (user == null)
                        return new Feedback<user>(false, Messages.GetUser_NotFound);

                    return new Feedback<user>(true, null, user);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<user>(false, Messages.GeneralError);
            }
        }

        public Feedback<user> UpdateUser(user c, IList<int> roleIds)
        {
            try
            {
                using (var entities = new OrmEntities())
                {
                    user user = entities.Users.Single(i => i.Id == c.Id);
                    user.UserStateId = c.UserStateId;
                    user.Ponit = c.Ponit;

                    // Cannot change admin email
                    if (user.Email.Equals(AppConfigs.AdminEmail))
                    {
                        return new Feedback<user>(false, Messages.CannotChangeAdminInfo);
                    }

                    //Remove from user roles
                    foreach (var a in entities.UserRoles.Where(t => t.UserId == c.Id))
                        entities.UserRoles.Remove(a);

                    //Add new roles for user
                    foreach (int itemId in roleIds)
                    {
                        UserRole userRole = new UserRole
                        {
                            UserId = c.Id,
                            RoleId = itemId
                        };
                        entities.UserRoles.Add(userRole);
                    }

                    entities.SaveChanges();

                    return new Feedback<user>(true, null, user);
                }
            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<user>(false, Messages.GeneralError);
            }
        }


        public Feedback<IList<UserState>> GetAllUserStates()
        {
            using (var entities = new OrmEntities())
            {
                try
                {
                    return new Feedback<IList<UserState>>(true, null, entities.UserStates.ToList());
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                    return new Feedback<IList<UserState>>(false);
                }
            }
        }
    }
}
